﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	ServiceLocator.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.ComponentModel;

namespace Smart.Common.Locator
{
	/// <summary>
	/// Service locator and configuration
	/// </summary>
	[Localizable(false)]
	public class ServiceLocator : IServiceLocator
	{
		public SPServicesInstance Services { get; set; }

		public ServiceLocator(SPServicesInstance services)
		{
			Services = services;
		}

		/// <summary>
		/// Services store
		/// </summary>
		private readonly SyncDictionary<long, ServiceLocatorInfo> _services = new SyncDictionary<long, ServiceLocatorInfo>();

		/// <summary>
		/// Return unique key
		/// </summary>
		protected long GetServiceKey(Type interfaceType, string key)
		{
			return
				interfaceType.GetHashCode() << 32 | (key.IsNullOrEmpty() ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(key));
		}

		/// <summary>
		/// Register service
		/// </summary>
		public void Register<TInterface, TClass>()
			where TClass : TInterface, new()
		{
			Register<TInterface, TClass>(null);
		}

		/// <summary>
		/// Register service
		/// </summary>
		public void Register<TInterface, TClass>(string key)
			where TClass : TInterface, new()
		{
			var it = typeof(TInterface);
			var ct = typeof(TClass);

			var sk = GetServiceKey(it, key);

			_services[sk] = new ServiceLocatorInfo { ClassType = ct, InterfaceType = it, Key = key };
		}

		/// <summary>
		/// Unregister service
		/// </summary>
		public void Unregister<TInterface>(string key)
		{
			var it = typeof(TInterface);

			var sk = GetServiceKey(it, key);

			_services.Remove(sk);
		}

		/// <summary>
		/// Create instance of service
		/// </summary>
		public TInterface GetInstance<TInterface>()
		{
			return GetInstance<TInterface>(null);
		}

		/// <summary>
		/// Create instance of service
		/// </summary>
		public TInterface GetInstance<TInterface>(string key)
		{
			var it = typeof(TInterface);

			var sk = GetServiceKey(it, key);

			var sli = _services[sk];

			if (sli == null)
				throw new TypeLoadException("Class not defined: " + key);

			return (TInterface)Activator.CreateInstance(sli.ClassType);
		}
	}
}